Jump to page sections

List installed software on Windows with PowerShell

The lightweight method I'll use for listing installed software, is registry lookups. The "folders"/keys I'm looking at are HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall and HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall. This captures both 64-bit applications (the former registry key) and 32-bit applications on 64-bit Windows (the latter registry key).

The WMI class Win32_Product could be used, but as I recall, it triggers unwanted behavior even when you simply want to enumerate/list it, and it actually verifies the packages, and can even cause changes to a system simply from being enumerated, based on what I've read (it gets enumerated when you call Get-WmiObject -Class Win32_Product). I notice Win32_Product has the tag "legacy" on docs.microsoft.com. So we will not use this. There's more on Win32_Product in a blog article from 2011 on devblogs.microsoft.com here.

We will use a couple of simple, lightweight, CPU- and memory-friendly registry lookups with the flexibility of PowerShell's associated scripting language.

It is easy to add chocolatey packages as well, without the install date, so I did. You can omit that code if you want.

$Installed = @(Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | 
    Select-Object DisplayName, DisplayVersion, Publisher, InstallDate)
$Installed += Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
    Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
$Installed = $Installed |
    Where-Object {$null -ne $_.DisplayName} |
    Sort-Object -Property DisplayName -Unique |
    ConvertTo-Csv -NoTypeInformation
# Add chocolatey packages if the "choco" command is available.
if (Get-Command -Name choco -ErrorAction SilentlyContinue) {
    $Installed += choco list -lo -r -y | 
        ForEach-Object {'"' + $_.Replace("|", '","') + '","Chocolatey",""'}
}
$InstalledString = $Installed -join "`n"
#Write-EventLog ... -Message $InstalledString # For instance captured in Splunk.
#Write-Verbose -Verbose $InstalledString
$Installed | Set-Content -LiteralPath .\installed_software.csv -Encoding UTF8

This is example code that assumes you want a CSV file. It can easily be altered to produce objects, should you need that (omit ConvertTo-Csv and handle choco output differently).

It might not capture all software, but it's likely the best one can generically do. You can add code to look for files and folders specific to your environment, if the software you use does not register itself properly. For instance using Test-Path.

Windows      Powershell      WMI      Software      Win32_Product      Registry          All Categories

Google custom search of this website only

Minimum cookies is the standard setting. This website uses Google Analytics and Google Ads, and these products may set cookies. By continuing to use this website, you accept this.

If you want to reward my efforts